package smartai.examples.speech.asr;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.vosk.Model;
import org.vosk.Recognizer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Slf4j
public class WakewordDetector {

    private final Recognizer recognizer;

    // 唤醒词配置
    private final List<String> wakewords;
    private final int detectionWindowSize; // 检测窗口大小（语音片段数）
    private final double confidenceThreshold; // 置信度阈值

    // 音频处理线程池
    private final ExecutorService processingExecutor = Executors.newSingleThreadExecutor();

    // 检测结果回调
    private WakewordListener listener;

    // 语音缓冲区，用于上下文分析
    private final CircularBuffer<String> recognitionBuffer;

    /**
     * 构造函数
     *
     * @param recognizer          Vosk模型路径
     * @param wakewords           唤醒词列表
     * @param detectionWindowSize 检测窗口大小
     * @param confidenceThreshold 置信度阈值
     */
    public WakewordDetector(Recognizer recognizer, List<String> wakewords, int detectionWindowSize, double confidenceThreshold) {
        // 初始化识别器
        this.recognizer = recognizer;

        // 初始化唤醒词（转为小写，便于匹配）
        this.wakewords = new ArrayList<>();
        for (String word : wakewords) {
            this.wakewords.add(word.toLowerCase().trim());
        }

        // 初始化检测参数
        this.detectionWindowSize = detectionWindowSize;
        this.confidenceThreshold = confidenceThreshold;

        // 初始化语音缓冲区
        this.recognitionBuffer = new CircularBuffer<>(detectionWindowSize);

        log.info("Vosk唤醒词检测器初始化完成，唤醒词: {}", wakewords);
    }

    /**
     * 处理音频数据
     *
     * @param audioData 16位PCM音频数据（单声道，16kHz）
     */
    public void processAudio(byte[] audioData) {
        if (audioData == null || audioData.length == 0) {
            return;
        }

        // 提交音频处理任务到线程池
        processingExecutor.submit(() -> {
            try {
                // 处理音频数据
                boolean isFinal = recognizer.acceptWaveForm(audioData, audioData.length);

                // 获取识别结果
                String result;
                if (isFinal) {
                    result = recognizer.getFinalResult();
                } else {
                    result = recognizer.getPartialResult();
                }

                // 解析结果并检测唤醒词
                detectWakewordInResult(result);

            } catch (Exception e) {
                log.error("处理音频数据出错", e);
            }
        });
    }

    /**
     * 从识别结果中检测唤醒词
     *
     * @param result 识别结果JSON字符串
     */
    private void detectWakewordInResult(String result) {
        try {
            log.info("detectWakewordInResult: {}", result);
            // 解析JSON结果
            JSONObject rootNode = JSONUtil.parseObj(result);
            String textNode = rootNode.getStr("text");

            if (ObjectUtil.isNotEmpty(textNode)) {
                String recognizedText = textNode.toLowerCase().trim();
                log.debug("识别到文本: {}", recognizedText);

                // 将结果添加到缓冲区
                recognitionBuffer.add(recognizedText);

                // 检查缓冲区中是否包含唤醒词
                checkForWakewords();
            }

            // 检查单个词的置信度
            JSONArray wordsNodeList = rootNode.getJSONArray("result");
            if (ObjectUtil.isNotEmpty(wordsNodeList)) {
                for (Object wordNode : wordsNodeList) {
                    if (!(wordNode instanceof JSONObject)) {
                        continue;
                    }
                    JSONObject wordObj = (JSONObject) wordNode;
                    String word = wordObj.get("word").toString().toLowerCase();
                    double confidence = wordObj.getDouble("conf");

                    // 如果单个词匹配唤醒词且置信度足够高
                    if (wakewords.contains(word) && confidence >= confidenceThreshold) {
                        triggerWakewordDetection(word, confidence);
                    }
                }
            }

        } catch (Exception e) {
            log.error("解析识别结果出错", e);
        }
    }

    /**
     * 检查缓冲区中是否包含唤醒词
     */
    private void checkForWakewords() {
        // 组合缓冲区中的所有文本
        StringBuilder combinedText = new StringBuilder();
        for (String text : recognitionBuffer.getAll()) {
            if (!text.isEmpty()) {
                combinedText.append(text).append(" ");
            }
        }
        String fullText = combinedText.toString().trim();

        // 检查是否包含任何唤醒词
        for (String wakeword : wakewords) {
            // 使用正则表达式检查整个文本中是否包含唤醒词
            Pattern pattern = Pattern.compile("\\b" + Pattern.quote(wakeword) + "\\b", Pattern.CASE_INSENSITIVE);
            if (pattern.matcher(fullText).find()) {
                triggerWakewordDetection(wakeword, 1.0); // 上下文匹配，置信度设为1.0
                break;
            }
        }
    }

    /**
     * 触发唤醒词检测回调
     */
    private void triggerWakewordDetection(String wakeword, double confidence) {
        log.info("检测到唤醒词: '{}'，置信度: {}", wakeword, confidence);

        // 清空缓冲区，避免重复触发
        recognitionBuffer.clear();

        // 调用回调
        if (listener != null) {
            listener.onWakewordDetected(wakeword, confidence);
        }
    }

    /**
     * 设置唤醒词检测监听器
     */
    public void setWakewordListener(WakewordListener listener) {
        this.listener = listener;
    }

    /**
     * 释放资源
     */
    public void shutdown() {
        processingExecutor.shutdown();
        try {
            if (!processingExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                processingExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            processingExecutor.shutdownNow();
        }
    }

    /**
     * 唤醒词检测监听器接口
     */
    public interface WakewordListener {
        void onWakewordDetected(String wakeword, double confidence);
    }

    /**
     * 循环缓冲区，用于存储最近的识别结果
     */
    private static class CircularBuffer<T> {
        private final T[] buffer;
        private int index = 0;
        private int size = 0;

        @SuppressWarnings("unchecked")
        public CircularBuffer(int capacity) {
            buffer = (T[]) new Object[capacity];
        }

        public void add(T item) {
            buffer[index] = item;
            index = (index + 1) % buffer.length;
            if (size < buffer.length) {
                size++;
            }
        }

        public List<T> getAll() {
            List<T> result = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                int pos = (index - size + i + buffer.length) % buffer.length;
                result.add(buffer[pos]);
            }
            return result;
        }

        public void clear() {
            index = 0;
            size = 0;
        }

        public int getSize() {
            return size;
        }
    }
}
